package gui;


import java.awt.Toolkit;
import java.awt.FlowLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Component;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JComponent;
import javax.swing.event.CaretListener;
import java.awt.event.KeyAdapter;
import javax.swing.event.CaretEvent;
import java.awt.event.KeyEvent;
import javax.swing.text.PlainDocument;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.BorderFactory;

/********************************************************************************************************************************
 * 

Title: JPanel was das Aussehen und verhalten von einem IP Address feld hat</p>
 *
 * 

Description: Steht unter der LGPL (c) by TAJ</p>
 *
 * 

Copyright: Copyright (c) 2007</p>
 *
 * 

Company: Taschek J�rg </p>
 *
 * @author Taschek Joerg
 * @version 1.0 Erstversion 10.08.2007
 * @versoin 2.0 28.08.2007 Kleine �nderungen an der Klasse selbst - liegt jetzt auf noch einem Panel um den schwarzen Rand zu haben
 * desweiteren gibt es einen Einf�g Modus, ist keine vollst�ndige IP ausgef�llt, so wird null zur�ckgegeben und eine kleine main
 * zum Testen ist in der Klasse
 *******************************************************************************************************************************/
public class JipTextfield
    extends JPanel
{
  /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
private boolean MOVE_ON_FULL = true;
  private JTextFieldIP fields[] = new JTextFieldIP[4];
  private JTextField sep[] = new JTextField[3];
  private boolean INSERT_MODE = false;

  /******************************************************************************************************************************
   * Standardkonstruktor f�r das Feld
   *****************************************************************************************************************************/
  public JipTextfield()
  {
    super(new FlowLayout(FlowLayout.LEFT,0,0));
    JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
    panel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
    for(int x = 0; x != fields.length; x++)
    {
      fields[x] = new JTextFieldIP();
      fields[x].setBorder(null);
      fields[x].setHorizontalAlignment(JTextField.CENTER);
      fields[x].setPreferredSize(new Dimension(25,25));
    }
    for(int x = 0; x != fields.length - 1; x++)
    {
      fields[x].setDocument(new LimitDocument(fields[x + 1]));
    }
    fields[fields.length - 1].setDocument(new LimitDocument(fields[0]));
    for(int x = 0; x != sep.length; x++)
    {
      sep[x] = new JTextField();
      sep[x].setFocusable(false);
      sep[x].setDocument(new NoWriteDocument());
      sep[x].setText(".");
      sep[x].setBorder(null);
      sep[x].setPreferredSize( new Dimension(5,25));
    }
    setBackgroundFields(Color.WHITE);
    panel.add(fields[0]);
    panel.add(sep[0]);
    panel.add(fields[1]);
    panel.add(sep[1]);
    panel.add(fields[2]);
    panel.add(sep[2]);
    panel.add(fields[3]);
    this.add(panel);
  }

  /******************************************************************************************************************************
   * main Methode zum Testen des IP Feldes
   * @param args String[]
   *****************************************************************************************************************************/
  public static void main(String args[])
  {
    javax.swing.JFrame frame = new javax.swing.JFrame();
    frame.getContentPane().setLayout(new java.awt.BorderLayout());
    final JipTextfield ipfield = new JipTextfield();
    ipfield.setIP("127.0.0.1");
    System.out.println("IP: " + ipfield.getIP());
    frame.getContentPane().add(ipfield, java.awt.BorderLayout.NORTH);
    javax.swing.JButton button = new javax.swing.JButton("GET IP");
    frame.getContentPane().add(button, java.awt.BorderLayout.SOUTH);
    final javax.swing.JLabel label = new javax.swing.JLabel("<nothing>");
    button.addActionListener(new java.awt.event.ActionListener(){
      public void actionPerformed(java.awt.event.ActionEvent e)
      {
        label.setText(ipfield.getIP());
      }
    }
    );
    frame.getContentPane().add(label, java.awt.BorderLayout.CENTER);
    frame.setSize(300,300);
    frame.setVisible(true);
  }

  /******************************************************************************************************************************
   * Methode gibt die IP Adresse zur�ck
   * @return String Falsch ung�ltige IP, gibt es null zur�ck
   *****************************************************************************************************************************/
  public String getIP()
  {
    StringBuffer strRet = new StringBuffer();
    for(int x = 0; x != fields.length; x++)
    {
      if(x > 0)
        strRet.append(".");
      //wenn ein Feld nicht bef�llt ist, dann null zur�ckgeben
      if(fields[x].getText() == null || fields[x].getText().trim().length() == 0)
        return null;
      strRet.append(fields[x].getText());
    }
    return strRet.toString();
  }

  /******************************************************************************************************************************
   * Methode setzt die IP Addresse auf die Felder
   * @param ipAddr String
   *****************************************************************************************************************************/
  public void setIP(String ipAddr)
  {
    String ips[] = ipAddr.split("\\.");
    if(ips == null || ips.length != 4)
      throw new RuntimeException("Not a valid ip address: " + ipAddr);
    for(int x = 0; x != fields.length; x++)
      fields[x].setText(ips[x]);
  }

  /******************************************************************************************************************************
   * Methode gibt f�r die Listener die IDs zur�ck
   * @param comp Component
   * @return int
   *****************************************************************************************************************************/
  private int getField(Component comp)
  {
    for(int x = 0; x != fields.length; x++)
      if(fields[x].equals(comp))
        return x;
    return -1;
  }

  /******************************************************************************************************************************
   * Setzt die Hintergrundfarbe
   * @param color Color
   *****************************************************************************************************************************/
  public void setBackgroundFields(Color color)
  {
    for(int x = 0; x != fields.length; x++)
      fields[x].setBackground(color);
    for(int x = 0; x != sep.length; x++)
      sep[x].setBackground(color);
  }

  /******************************************************************************************************************************
   *
   * @return Color
   *****************************************************************************************************************************/
  public Color getBackgroundFields()
  {
    return fields[0].getBackground();
  }

  /******************************************************************************************************************************
   * Setzt die Vordergrundfarbe
   * @param color Color
   *****************************************************************************************************************************/
  public void setForegroundFields(Color color)
  {
    for(int x = 0; x != fields.length; x++)
      fields[x].setForeground(color);
    for(int x = 0; x != sep.length; x++)
      sep[x].setForeground(color);
  }

  /******************************************************************************************************************************
   *
   * @return Color
   *****************************************************************************************************************************/
  public Color getForegroundFields()
  {
    return fields[0].getForeground();
  }

  /******************************************************************************************************************************
   *
   * @return JComponent
   *****************************************************************************************************************************/
  public JComponent getFinishFocus()
  {
    return ((LimitDocument)fields[fields.length - 1].getDocument()).getNextFocus();
  }

  /******************************************************************************************************************************
   * Gibt die Komponente an, nachdem die ganze IP eingegeben wurde wohin der Focus kommt
   * @param nextFocus JComponent
   *****************************************************************************************************************************/
  public void setFinishFocus(JComponent nextFocus)
  {
    ((LimitDocument)fields[fields.length - 1].getDocument()).setNextFocus(nextFocus);
  }

  /******************************************************************************************************************************
   *
   * @return boolean
   *****************************************************************************************************************************/
  public boolean isMovingOnFull()
  {
    return MOVE_ON_FULL;
  }

  /******************************************************************************************************************************
   * Setzt wenn die IP Adresse eingegeben worden ist, ob man aufs n�chste Feld springen soll
   * @param aValue boolean
   *****************************************************************************************************************************/
  public void setMovingOnFull(boolean aValue)
  {
    MOVE_ON_FULL = aValue;
  }

  /*****************************************************************************************************************************
   *
   * 

Title: Eigenes TextField welches die Listener dranh�ngt und sich den caret Event merkt</p>
   *
   * 

Description: Steht unter LGPL</p>
   *
   * 

Copyright: Copyright (c) 2007</p>
   *
   * 

Company: POS Systemhaus</p>
   *
   * @author Taschek Joerg
   * @version 1.0 Erstversion 10.08.2007
   *****************************************************************************************************************************/
  private class JTextFieldIP extends JTextField
  {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private boolean event = false;
    public JTextFieldIP()
    {
      super();
      this.addCaretListener(new CaretListener()
      {
        public void caretUpdate(CaretEvent e)
        {
          event = true;
        }
      });
      this.addKeyListener(new KeyAdapter()
      {
        private boolean pressed = false;
        public void keyReleased(KeyEvent e)
        {
          if(pressed)
          {
            if(e.getKeyCode() == KeyEvent.VK_LEFT)
            {
              int id = getField(e.getComponent());
              if(id >= 1)
              {
                if(!event)
                  fields[--id].requestFocus();
                else
                  event = false;
              }
            }
            else if(e.getKeyCode() == KeyEvent.VK_RIGHT)
            {
              int id = getField(e.getComponent());
              if(id != -1 && id < fields.length - 1)
              {
                if(!event)
                  fields[++id].requestFocus();
                else
                  event = false;
              }
            }
            else if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE)
            {
              int id = getField(e.getComponent());
              if(id >= 1) //beim 0er feld wird da nix gemacht
              {
                if(fields[id].getText().trim().length() == 0) //wenn nix drinnen ist
                {
                  if(((LimitDocument)fields[id].getDocument()).isEmpty())
                  {
                    fields[--id].requestFocus();
                    fields[id].getCaret().setDot(fields[id].getText().length()); //setzt den Cursor nach ganz hinten
                  }
                  ((LimitDocument)fields[id].getDocument()).setEmpty(true);
                }
              }
            }
            else if(e.getKeyCode() == KeyEvent.VK_INSERT)
              INSERT_MODE = !INSERT_MODE; //umkehren des aktuellen Status
            pressed = false;
          }
        }

        public void keyPressed(KeyEvent e)
        {
          if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE || e.getKeyCode() == KeyEvent.VK_RIGHT || 
             e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_INSERT)
            pressed = true;
        }
      });
    }
  }

  /******************************************************************************************************************************
   *
   * 

Title: Dokument l�sst keine Zahlen > 255 eingeben und bei einem "." als Eingabe springt es auf das n�chste Feld</p>
   *
   * 

Description: Unter LGPL</p>
   *
   * 

Copyright: Copyright (c) 2007</p>
   *
   * 

Company: POS Systemhaus</p>
   *
   * @author Taschek Joerg
   * @version 1.0 Erstversion 10.08.2007
   *****************************************************************************************************************************/
  private class LimitDocument extends PlainDocument
  {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JComponent nextFocus = null;
    private boolean empty = false;
    public LimitDocument(JComponent nextFocus)
    {
      setNextFocus(nextFocus);
      this.addDocumentListener(new DocumentListener()
      {
        public void insertUpdate(DocumentEvent e)
        {
          if(getLength() > 0)
            empty = false;
        }

        public void removeUpdate(DocumentEvent e)
        {
        }

        public void changedUpdate(DocumentEvent e)
        {
          if(getLength() > 0)
            empty = false;
        }
      });
    }

    public boolean isEmpty()
    {
      return empty;
    }

    public void setEmpty(boolean aValue)
    {
      this.empty = aValue;
    }

    public void setNextFocus(JComponent nextFocus)
    {
      this.nextFocus = nextFocus;
    }

    public JComponent getNextFocus()
    {
      return this.nextFocus;
    }

    public void insertString(int offset, String s, AttributeSet attributeSet) throws BadLocationException
    {
      if(s != null && s.equals("."))
      {
        if(nextFocus != null && nextFocus.isEnabled())
          nextFocus.requestFocus();
      }
      if(!INSERT_MODE)
      {
        if (getLength() + (s != null ? s.length() : 0) > 3)
          return;
      }
      try{
        Integer.parseInt(s);
      }
      catch(Exception ex)   //only allow integer values
      {
        Toolkit.getDefaultToolkit().beep(); //macht ein D�T
        return ;
      }
      try{
        if(!INSERT_MODE)
        {
          StringBuffer strBuf = new StringBuffer(getText(0, getLength()));
          strBuf.insert(offset, s);
          int i = Integer.parseInt(strBuf.toString());
          if (i > 255)
          {
            Toolkit.getDefaultToolkit().beep();
            return;
          }
        }
        else
        {
          StringBuffer strBuf = new StringBuffer(getText(0, getLength()));
          strBuf.replace(offset, offset + s.length(),s);
          int i = Integer.parseInt(strBuf.toString());
          if (i > 255)
          {
            Toolkit.getDefaultToolkit().beep();
            return;
          }
          remove(offset,s.length());
        }
      }catch(Exception ex)
      {
        Toolkit.getDefaultToolkit().beep();
      }
      super.insertString(offset,s, attributeSet);
      if(MOVE_ON_FULL)
      {//wenn es nicht der INSERT Modus ist und die l�nge von 3 erreicht ist oder wenn es im insert Modus ist und er auf der 3ten(2) position ist
        if ( ( !INSERT_MODE && getLength() == 3 ) || (INSERT_MODE && offset == 2) )
        {
          if (nextFocus != null && nextFocus.isEnabled())
          {
            if(nextFocus instanceof JTextFieldIP)
              ((JTextFieldIP)nextFocus).getCaret().setDot(0); //setzt den Fokus auf das vorderste Zeichen
            nextFocus.requestFocus();
          }
        }
      }
    }
  }

  /******************************************************************************************************************************
   *
   * 

Title: Klasse l�sst keine Eingaben in einem Textfeld zu</p>
   *
   * 

Description: Steht unter LGPL</p>
   *
   * 

Copyright: Copyright (c) 2007</p>
   *
   * 

Company: POS Systemhaus</p>
   *
   * @author Taschek Joerg
   * @version 1.0 Erstversion 10.08.2007
   *****************************************************************************************************************************/
  private class NoWriteDocument extends PlainDocument
  {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void insertString(int offset, String s, AttributeSet attributeSet) throws BadLocationException
    {
      super.remove(0, getLength());
      super.insertString(0,".",attributeSet);
    }
  }
}

